#include "riscv.h"
#include "common.h"

void main();
// 定义内核栈，在entry.S中为每个hart分配4096字节的空间，NCPU为hart数，在param.h中定义
__attribute__ ((aligned(16))) char stack0[4096 * NCPU];

// 从entry.S跳转过来，此时处于机器模式, sp指向stack0中的位置
void start(void) {
    // MPP表示M模式之前的模式，mret（Machine Mode Return），即从M模式返回到之前的模式
    // 将MPP置为1，用mret跳转回原来的模式 <=> M模式切换到S模式
    uint64 x = r_csr(MSTATUS);   // 读取MSTATUS寄存器的值
    x &= ~MSTATUS_MPP;                  // 将MPP位清零，取反其余位为1，与运算不变；MPP为原来为0，取反与仍然为0，原来为1，取反与也为0
    x |= MSTATUS_MPP_S;                 // 将MPP位设置为1，即设置为Supervisor模式
    w_csr(MSTATUS, x);                  // 将修改后的值写回MSTATUS寄存器
    
    // 先禁用分页，分页所需环境还未初始化，初始化内核需要直接使用物理地址
    w_csr(SATP, 0);

    // 委托所有异常和中断给S模式处理
    w_csr(MEDELEG, 0xffff);
    w_csr(MIDELEG, 0xffff);
    // 开启S模式对应的中断，与中断委托寄存器配合使用
    uint64 sie = r_csr(SIE);
    w_csr(SIE, sie | SIE_SEIE | SIE_STIE | SIE_SSIE);

    // 设置S模式可访问的物理地址和权限
    w_csr(PMPADDR0, 0x3fffffffffffff);  // 表示可访问所有地址
    w_csr(PMPCFG0, 0xf);                   // 表示对访问地址，可读、可写、可执行

    // 读取mhartid中的值并存入tp寄存器，以便在S模式下可以直接获取到hartid
    int hartid = r_csr(MHARTID);
    w_tp(hartid);

    w_csr(MEPC, (uint64)main);   // 将main函数地址写到MEPC寄存器
    asm volatile("mret");               // 切换到S模式并跳转到main函数
}